<?php

class Supervisor extends Actor
{
    public $strategy='OneForOne';
    public $intensity=1;
    public $period=-1;
    //没用
    public static function start($args)
    {
        return static::spawn_opt([$class,'init'], $args, [
            'addr'=> Booru::$reg_addr 
        ]);
    }
    //没用
    public static function start_link($args)
    {
        return static::spawn_opt([$class,'init'], $args, [
            'addr' => Booru::$reg_addr,
            'link' => self::self(), 
        ]);
    }
    public function flags($strategy, $intensity , $period )
    {
        $this->strategy = $strategy;
        $this->intensity = $intensity;
        $this->period = $period;
    }
    /**
     * @param [type] $classOrfunc 启动函数
     * @param [type] $restart 重启方式
     * @param [type] $delay 重启间隔
     * @return void
     */
    public function worker($classOrfunc, $restart = 0, $delay = 0)
    {
        $this->opts[] = [ $classOrfunc , [ ] ,[
            'addr'=>'worker',//进程池创建
            'class'=>Actor::class,
            'link'=>$this->self(),
        ] ];
    }
    /**
     * @param [type] $classOrfunc 启动函数
     * @param [type] $restart 重启方式
     * @param [type] $delay 重启间隔
     * @return void
     */
    public function service($classOrfunc, $restart = 0, $delay = 0)
    {
        $this->opts[] = [ $classOrfunc , [ ] ,[
            'addr'=>'service',//新进程创建
            'link'=>$this->self(),
            'main'=>true, 
        ] ];
    }
    /**
     * @param [type] $classOrfunc 启动函数
     * @param [type] $restart 重启方式
     * @param [type] $delay 重启间隔
     * @return void
     */
    public function supervise($classOrfunc, $restart = 0, $delay = 0)
    {
        $this->opts[] = [ $classOrfunc , [ ] ,[
            'addr' => Booru::$reg_addr,//
            'link' => $this->self(),
            'class'=> Supervisor::class, 
        ] ];
    }

    public function init()
    {
        return;
    }

    public function after($result){ 
        $this->trapexit(true);  
        yield from $this->{'on'.$this->strategy}();
    }
    
    public function onOneForAll(){ 
        while(1){ 
            foreach ($this->opts as $index => $value){ 
                $childs[$index] = yield Actor::spawn(...$value);   
            }    
            $coid = yield $this->receive(function($atom){
                if($atom[0]=='EXIT'){
                    return $atom[1];
                }
            });     
            foreach ($childs as $index=>$coid) { 
                $this->unlink($coid);
                $this->exit($coid,'restart'); 
            }  
            yield Actor::delay($this->intensity);  
        }
    }

    public function onOneForOne(){  
        foreach ($this->opts as $index => $value){ 
            $childs[$index] = yield Actor::spawn(...$value);  
        }   
        while(1){
            $coid = yield $this->receive(function($atom){
                if($atom[0]=='EXIT'){
                    return $atom[1];
                }
            });    
            $index = array_search($coid,$childs);
            if($index===false){
                throw new Exception("Error Processing Request", 1);
            }
            $childs[$index] =  yield Actor::spawn(...$this->opts[$index]);  
            
            yield Actor::delay($this->intensity);   
        }

    }
 
}
